#include "quant.h"
#include "encoder_logger.h"

// 按照量化参数采用6个基本数据
#define QUANT_BAIC_SIZE 6

static const uint16_t quant4_scale[QUANT_BAIC_SIZE][3] =
{
    { 13107, 8066, 5243 },
    { 11916, 7490, 4660 },
    { 10082, 6554, 4194 },
    {  9362, 5825, 3647 },
    {  8192, 5243, 3355 },
    {  7282, 4559, 2893 },
};

static const uint8_t dequant4_scale[QUANT_BAIC_SIZE][3] =
{
    { 10, 13, 16 },
    { 11, 14, 18 },
    { 13, 16, 20 },
    { 14, 18, 23 },
    { 16, 20, 25 },
    { 18, 23, 29 }
};

#define DIV(n,d) (((n) + ((d)>>1)) / (d))
#define SHIFT(x,s) ((s)<=0 ? (x)<<-(s) : ((x)+(1<<((s)-1)))>>(s))

// 和h264相比取消的8x8量化表
int h264_cqm_init(quant_t *quant, int sps_scaling)
{
    int def_quant4[QUANT_BAIC_SIZE][16] = {0};
    int def_dequant4[QUANT_BAIC_SIZE][16] = {0};
    int quant4_mf[CQM_BUTT][QUANT_BAIC_SIZE][16] = {0};
    int deadzone[4] = { 21,11,21,11};

    for( int q = 0; q < QUANT_BAIC_SIZE; q++ )
    {
        for( int i = 0; i < 16; i++ )
        {
            int j = (i & 1) + ((i >> 2) & 1);
            def_dequant4[q][i] = dequant4_scale[q][j];
            def_quant4[q][i]   =   quant4_scale[q][j];
        }
    }


    for( int q = 0; q < QUANT_BAIC_SIZE; q++ )
    {
        for( int i_list = 0; i_list < CQM_BUTT; i_list++ )
        {
            for( int i = 0; i < 16; i++ )
            {
                quant->dequant4_mf[i_list][q][i] = def_dequant4[q][i] * sps_scaling;
                quant4_mf[i_list][q][i] = DIV(def_quant4[q][i] * 16, sps_scaling);
            }
        }
    }

    for( int q = 0; q <= QP_MAX_SPEC; q++ )
    {
        int j;
        for( int i_list = 0; i_list < CQM_BUTT; i_list++ )
            for( int i = 0; i < 16; i++ )
            {
                quant->unquant4_mf[i_list][q][i] = (1ULL << (q/6 + 15 + 8)) / quant4_mf[i_list][q%6][i];
                j = SHIFT(quant4_mf[i_list][q%6][i], q/6 - 1);
                quant->quant4_mf[i_list][q][i] = (uint16_t)j;
                if( j == 0 )
                {
                    ERR_LOG("error quant4_mf[i_list][q][i] = %d\n", j);
                    continue;
                }
                // round to nearest, unless that would cause the deadzone to be negative
                quant->quant4_bias[i_list][q][i] = X264_MIN( DIV(deadzone[i_list]<<10, j), (1<<15)/j );
                quant->quant4_bias0[i_list][q][i] = (1<<15)/j;
            }

    }

    return 0;
}

#define QUANT_ONE( coef, mf, f ) \
{ \
    if( (coef) > 0 ) \
        (coef) = ((f) + (uint32_t)(coef)) * (mf) >> 16; \
    else \
        (coef) = -(int32_t)(((f) + (uint32_t)(-coef)) * (mf) >> 16); \
    nz |= (coef); \
}

int quant_4x4x4( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] )
{
    int nza = 0;
    for( int j = 0; j < 4; j++ )
    {
        int nz = 0;
        for( int i = 0; i < 16; i++ )
            QUANT_ONE( dct[j][i], mf[i], bias[i] );
        nza |= (!!nz)<<j;
    }
    return nza;
}

#define DEQUANT_SHL( x ) \
    dct[x] = ( dct[x] * dequant_mf[i_mf][x] ) * (1 << i_qbits)

#define DEQUANT_SHR( x ) \
    dct[x] = ( dct[x] * dequant_mf[i_mf][x] + f ) >> (-i_qbits)

void dequant_4x4( dctcoef dct[16], int dequant_mf[6][16], int i_qp )
{
    const int i_mf = i_qp%6;
    const int i_qbits = i_qp/6 - 4;

    if( i_qbits >= 0 )
    {
        for( int i = 0; i < 16; i++ )
            DEQUANT_SHL( i );
    }
    else
    {
        const int f = 1 << (-i_qbits-1);
        for( int i = 0; i < 16; i++ )
            DEQUANT_SHR( i );
    }
}

int quant_4x4_dc( dctcoef dct[16], int mf, int bias )
{
    int nz = 0;
    for( int i = 0; i < 16; i++ ) {
        QUANT_ONE( dct[i], mf, bias );
    }
    if (nz == 0) {
        return 0;
    }
    return 1;
}

void dequant_4x4_dc( dctcoef dct[16], int dequant_mf[6][16], int i_qp )
{
    const int i_qbits = i_qp/6 - 6;

    if( i_qbits >= 0 )
    {
        const int i_dmf = dequant_mf[i_qp%6][0] << i_qbits;
        for( int i = 0; i < 16; i++ )
            dct[i] *= i_dmf;
    }
    else
    {
        const int i_dmf = dequant_mf[i_qp%6][0];
        const int f = 1 << (-i_qbits-1);
        for( int i = 0; i < 16; i++ )
            dct[i] = ( dct[i] * i_dmf + f ) >> (-i_qbits);
    }
}

int quant_2x2_dc( dctcoef dct[4], int mf, int bias )
{
    int nz = 0;
    QUANT_ONE( dct[0], mf, bias );
    QUANT_ONE( dct[1], mf, bias );
    QUANT_ONE( dct[2], mf, bias );
    QUANT_ONE( dct[3], mf, bias );
    return !!nz;
}

void idct_dequant_2x2_dc(dctcoef dct[4], dctcoef dct4x4[4][16], int dequant_mf[6][16], int i_qp)
{
    int d0 = dct[0] + dct[1];
    int d1 = dct[2] + dct[3];
    int d2 = dct[0] - dct[1];
    int d3 = dct[2] - dct[3];
    int dmf = dequant_mf[i_qp % 6][0] << i_qp / 6;
    dct4x4[0][0] = (d0 + d1) * dmf >> 5;
    dct4x4[1][0] = (d0 - d1) * dmf >> 5;
    dct4x4[2][0] = (d2 + d3) * dmf >> 5;
    dct4x4[3][0] = (d2 - d3) * dmf >> 5;
}
